package com.oig.sys.workflow.controller;


import com.oig.common.constants.CommonEnum;
import com.oig.common.exception.BadRequestException;
import com.oig.common.exception.ServiceException;
import com.oig.common.module.SysResponse;
import com.oig.common.module.ValidListDto;
import com.oig.common.validator.GroupAdd;
import com.oig.common.validator.GroupEdit;
import com.oig.sys.log.annotation.SysLog;
import com.oig.sys.security.util.SecurityUtil;
import com.oig.sys.workflow.app.IAppCronJobService;
import com.oig.sys.workflow.dto.CronJobDto;
import com.oig.sys.workflow.schedule.CronJobManager;
import com.oig.sys.workflow.vo.CronJobVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.List;


/**
 * 本地简单的定时任务,只支持调用http接口
 *
 * 预警通知其实可以用报表工具做
 * 普通定时任务调度，可以用xxl-job
 * 多个任务有序执行的，可以用conductor来做任务编排
 *
 *
 * 但conductor配置怎么做？
 * 如：预警通知的配置
 * 预警项的定时任务、通知的任务分开设计？
 *
 */
@Tag(name = "定时任务管理")
@RestController
@RequestMapping("/cronJob")
@Slf4j
@RequiredArgsConstructor
public class TbCronJobController {


    private final IAppCronJobService appCronJobService;
    private final CronJobManager cronJobManager;


    @PreAuthorize("@pms.hasPermission('/cronJob/add')")
    @SysLog(value="添加定时任务",apiUrl="/cronJob/add")
    @Operation(summary = "添加定时任务")
    @PostMapping(value = "/add")
    public CronJobVo addCronJob(@RequestBody @Validated(GroupAdd.class) CronJobDto cronJobDto){
        log.info("add cron job, {}", cronJobDto);
        if (SecurityUtil.getDefineUserMain().getTenantId()!=0){
            throw new BadRequestException("租户无权操作");
        }
        cronJobDto.setCreateUserId(SecurityUtil.getDefineUserMain().getId());
        cronJobDto.setCreateUserName(SecurityUtil.getDefineUserMain().getRealName());
        cronJobDto.setCreateTime(new Date());
        cronJobDto.setLastUpdateId(cronJobDto.getCreateUserId());
        cronJobDto.setLastUpdateName(cronJobDto.getCreateUserName());
        cronJobDto.setLastUpdateTime(cronJobDto.getCreateTime());
        cronJobDto.setTenantId(SecurityUtil.getDefineUserMain().getTenantId());
        cronJobDto.setTenantName(SecurityUtil.getDefineUserMain().getTenantName());
        CronJobVo cronJobVo = this.appCronJobService.addCronJob(cronJobDto);
        if (CommonEnum.FlagEnum.TRUE_FLAG.getCode().equals(cronJobVo.getEnable())){
            this.cronJobManager.startJob(cronJobVo);
        }
        return cronJobVo;
    }

    private CronJobVo checkRole(Integer cronJobId){
        CronJobVo cronJob = this.appCronJobService.getCronJob(cronJobId);
        if (cronJob==null){
            throw new BadRequestException("任务不存在") ;
        }
        SecurityUtil.getDefineUserMain().checkTenantPermission(cronJob.getTenantId());
        return cronJob;
    }

    @PreAuthorize("@pms.hasPermission('/cronJob/update')")
    @SysLog(value="修改定时任务",apiUrl="/cronJob/update")
    @Operation(summary = "修改定时任务")
    @PostMapping(value = "/update")
    public CronJobVo updateCronJob(@RequestBody @Validated(GroupEdit.class) CronJobDto cronJobDto){
        log.info("update cron job, {}", cronJobDto);
        this.checkRole(cronJobDto.getId());
        cronJobDto.setLastUpdateId(SecurityUtil.getDefineUserMain().getId());
        cronJobDto.setLastUpdateName(SecurityUtil.getDefineUserMain().getRealName());
        cronJobDto.setLastUpdateTime(new Date());
        CronJobVo cronJobVo =  this.appCronJobService.updateCronJob(cronJobDto);
        if (CommonEnum.FlagEnum.TRUE_FLAG.getCode().equals(cronJobVo.getEnable())){
            this.cronJobManager.stopJob(cronJobVo.getId());
            this.cronJobManager.startJob(cronJobVo);
        }
        return cronJobVo;
    }

    @PreAuthorize("@pms.hasPermission('/cronJob/cancel')")
    @SysLog(value="删除定时任务",apiUrl="/cronJob/cancel")
    @Operation(summary = "删除定时任务")
    @PostMapping(value = "/cancel/{jobId}")
    public SysResponse<Integer> cancelCronJob(@PathVariable("jobId") Integer jobId){
        log.info("cancel cron job id={}", jobId) ;
        this.checkRole(jobId);
        this.appCronJobService.cancelCronJob(jobId);
        this.cronJobManager.stopJob(jobId);
        return SysResponse.ok(jobId,"删除自动化规则配置成功");
    }


    @Operation(summary = "查看定时任务详细信息")
    @PostMapping(value = "/info/{jobId}")
    public CronJobVo getCronJob(@PathVariable("jobId") Integer jobId){
        log.info(" get cron job id=:{}", jobId);
        return this.appCronJobService.getCronJob(jobId);
    }


    @PreAuthorize("@pms.hasPermission('/cronJob/execute')")
    @SysLog(value="执行定时任务",apiUrl="/cronJob/execute")
    @Operation(summary = "立即执行")
    @PostMapping(value = "/execute/{jobId}")
    public SysResponse<Integer> execute(@PathVariable(value = "jobId") Integer jobId){
        log.info("立即执行任务:{}", jobId);
        CronJobVo cronJobVo = this.checkRole(jobId);
        boolean r = cronJobManager.executeJob(cronJobVo);
        if (!r){
            throw new ServiceException("任务执行异常") ;
        }
        return SysResponse.ok(jobId,"执行任务成功");
    }

    @PreAuthorize("@pms.hasPermission('/cronJob/disable')")
    @SysLog(value="停止定时任务",apiUrl="/cronJob/disable")
    @Operation(summary = "停止定时任务")
    @PostMapping(value = "/disable")
    public void disable(@RequestBody ValidListDto<Integer> jobIdListDto){
        log.info("停用定时任务:{}", jobIdListDto);
        this.appCronJobService.disableJob(jobIdListDto.getList());
        jobIdListDto.getList().forEach(cronJobManager::stopJob);
    }


    @PreAuthorize("@pms.hasPermission('/cronJob/enable')")
    @SysLog(value="启动定时任务",apiUrl="/cronJob/enable")
    @Operation(summary = "启动定时任务")
    @PostMapping(value = "/enable")
    public void enable(@RequestBody ValidListDto<Integer> jobIdListDto){
        log.info("启用任务:{}", jobIdListDto);
        List<CronJobVo> cronJobVoList = this.appCronJobService.enableJob(jobIdListDto.getList());
        cronJobVoList.forEach(cronJobManager::startJob);
    }


}
